package com.itheima.aspect;

import com.itheima.aspect.annotation.OperLog;
import com.itheima.common.BaseContext;
import com.itheima.pojo.OperationLog;
import com.itheima.service.OperationLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareAnnotation;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.TimerTask;

/**
 * reggie-com.itheima.aspect
 * Administrator
 * 2023-03-15
 * 16:00
 */
//交给SPRING管理
@Component
//标识这是切面
@Aspect
public class OperationAspect {

    //1.切入点表达式:标识哪些方法是切入点(需要进行增强的方法)
    //之前excution(修饰符 返回值 包路径 类方法参数)
    //annotation 只要加入这个注解就是切入点方法
    @Pointcut("@annotation(com.itheima.aspect.annotation.OperLog)")
    private void operationMethod(){}

    @Autowired
    private OperationLogService operationLogService;

    //3.切面:如何对哪些方法,进行哪些增强

    @Around("operationMethod()")
    //2.通知:具体的增强代码
    public Object operationLogHandle(ProceedingJoinPoint pjp){

        OperationLog operationLog = new OperationLog();

        //获取目标方法 MethodSignature包含目标方法所有信息 也包含目标方法
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        //获取目标方法上面的注释
        OperLog annotation = method.getAnnotation(OperLog.class);
        //获取注解的属性
        String value = annotation.value();
        String username = annotation.username();


        //设置添加的日志内容
        operationLog.setOperation_action(value);
        operationLog.setUser_id(BaseContext.getCurrentId());
        operationLog.setOperation_time(LocalDateTime.now());


        //获取目标参数
        Object[] args = pjp.getArgs();

        Object result=null;

        try {
            //前置增强
            result = pjp.proceed(args);
            //后置增强
        } catch (Throwable throwable) {
            //异常增强
            //throwable.printStackTrace();
            //用了更新内容 要重新设置内容
            operationLogService.save(operationLog);
        } finally {
            //使与主线程并行 以免增强方法出错 导致主线程无法执行
            new AsyncManager().execute(new TimerTask() {
                @Override
                public void run() {
                    operationLogService.save(operationLog);
                }
            });

            //返回后增强
        }
        return result;
    }
}
